#include "stdafx.h"
#include "SocketsConnectionManager.h"

using namespace Adaptive::Network::Sockets;

/*------------------------------------------------------------------------
 * Constructor / Dispose / Destructor Methods
 *----------------------------------------------------------------------*/
#pragma region Constructor / Dispose / Destructor Methods
SocketsConnectionManager::SocketsConnectionManager()
{
	_connections = gcnew SocketsConnectionCollection();
}
SocketsConnectionManager::~SocketsConnectionManager()
{
	if (!Disposed)
	{
		CloseAll();
		if (_connections != nullptr)
		{
			_connections->ClearAndDispose();
			delete(_connections);
		}
	}
	_connections = nullptr;	
}
SocketsConnectionManager::!SocketsConnectionManager()
{
	if (!Disposed)
	{
		CloseAll();
		if (_connections != nullptr)
		{
			_connections->ClearAndDispose();
			delete(_connections);

		}
	}
	_connections = nullptr;	
}
#pragma endregion

/*------------------------------------------------------------------------
 * Public Properties
 *----------------------------------------------------------------------*/
#pragma region Public Properties
int SocketsConnectionManager::Count::get()
{
	int returnValue = 0;

	if (_connections != nullptr)
		returnValue = _connections->Count;

	return returnValue;
}
#pragma endregion

/*------------------------------------------------------------------------
 * Public Methods / Functions
 *----------------------------------------------------------------------*/
#pragma region Public Methods / Functions

void SocketsConnectionManager::Add(ISocketConnection^ newInstance)
{
	if (newInstance != nullptr)
	{
		System::Threading::Thread::BeginCriticalRegion();

		_connections->Add(newInstance);
		if (newInstance->GetType() == SocketsClient::typeid)
		{
			((SocketsClient^)newInstance)->DataReceived += gcnew DataReceivedEventHandler(this, &SocketsConnectionManager::HandleDataReception);
			((SocketsClient^)newInstance)->DataSent += gcnew DataSentEventHandler(this, &SocketsConnectionManager::HandleDataSend);
			((SocketsClient^)newInstance)->Disconnected += gcnew EventHandler(this, &SocketsConnectionManager::HandleDisconnect);
		}
		else if (newInstance->GetType() == SocketsConnection::typeid)
		{
			((SocketsConnection^)newInstance)->DataReceived += gcnew DataReceivedEventHandler(this, &SocketsConnectionManager::HandleDataReception);
			((SocketsConnection^)newInstance)->DataSent += gcnew DataSentEventHandler(this, &SocketsConnectionManager::HandleDataSend);
			((SocketsConnection^)newInstance)->Disconnected += gcnew EventHandler(this, &SocketsConnectionManager::HandleDisconnect);
		}
		System::Threading::Thread::EndCriticalRegion();

	}
}
void SocketsConnectionManager::AddRange(array<ISocketConnection^>^ newInstanceList)
{
	for each(ISocketConnection^ item in newInstanceList)
		Add(item);
}
void SocketsConnectionManager::CloseAll()
{
	SocketsClient^ item = nullptr;
	SocketsConnection^ connItem = nullptr;

	System::Threading::Thread::BeginCriticalRegion();

	//Close TCP.
	if (_connections != nullptr)
	{
		_connections->MoveFirst();
		while (!_connections->Eof)
		{
			_connections->Value->Close();
			_connections->MoveNext();
		}

		//Close and dispose of objects.
		_connections->MoveFirst();
		while (!_connections->Eof)
		{
			if (_connections->Value->GetType() == SocketsClient::typeid)
			{
				item = (SocketsClient^)_connections->Value;
				
				item->DataReceived -= gcnew DataReceivedEventHandler(this, &SocketsConnectionManager::HandleDataReception);
				item->DataSent -= gcnew DataSentEventHandler(this, &SocketsConnectionManager::HandleDataSend);
				item->Disconnected -= gcnew EventHandler(this, &SocketsConnectionManager::HandleDisconnect);
				delete(item);
			}
			else if (_connections->Value->GetType() == SocketsConnection::typeid)
			{
				connItem = (SocketsConnection^)_connections->Value;
				connItem->DataReceived -= gcnew DataReceivedEventHandler(this, &SocketsConnectionManager::HandleDataReception);
				connItem->DataSent -= gcnew DataSentEventHandler(this, &SocketsConnectionManager::HandleDataSend);
				connItem->Disconnected -= gcnew EventHandler(this, &SocketsConnectionManager::HandleDisconnect);
				delete(connItem);
			}
			_connections->Value->Close();
			_connections->MoveNext();
		}

		_connections->ClearAndDispose();
	}
	System::Threading::Thread::EndCriticalRegion();
}
void SocketsConnectionManager::AsyncCloseAll()
{
	Thread^ newThread = nullptr;

	newThread = gcnew Thread(gcnew ThreadStart(this, &SocketsConnectionManager::CloseAll));
	newThread->IsBackground = true;
	newThread->Priority = System::Threading::ThreadPriority::AboveNormal;
	newThread->Start();
}
#pragma endregion

/*------------------------------------------------------------------------
 * Event Methods / Functions
 *----------------------------------------------------------------------*/
#pragma region Event Methods / Functions
void SocketsConnectionManager::OnDataReceived(ISocketConnection^ client, DataReceivedEventArgs^ e)
{
	DataReceived(client, e);
}
void SocketsConnectionManager::OnDataSent(ISocketConnection^ client, DataSentEventArgs^ e)
{
	DataSent(client, e);
}
void SocketsConnectionManager::OnClientDisconnect(ConnectionEventArgs^ e)
{
	ClientDisconnect(this, e);
}
#pragma endregion

/*------------------------------------------------------------------------
 * Private Methods / Functions
 *----------------------------------------------------------------------*/
#pragma region Private Methods / Functions

void SocketsConnectionManager::HandleDataReception(Object^ sender, DataReceivedEventArgs^ e)
{
	OnDataReceived((ISocketConnection^)sender, e);
}
void SocketsConnectionManager::HandleDataSend(Object^ sender, DataSentEventArgs^ e)
{
	OnDataSent((ISocketConnection^)sender, e);
}
void SocketsConnectionManager::HandleDisconnect(Object^ sender, EventArgs^ e)
{
	ConnectionEventArgs^ newArgs = nullptr;

	newArgs = gcnew ConnectionEventArgs((ISocketConnection^)sender);
	OnClientDisconnect(newArgs);
	delete(newArgs);
}

#pragma endregion
